package org.mte.sakn.log;

import java.util.Date;

import org.apache.log4j.Layout;
import org.apache.log4j.Level;
import org.apache.log4j.helpers.Transform;
import org.apache.log4j.spi.LoggingEvent;
import org.mte.sakn.util.DateUtil;

/**
 * HTMLLayout
 *
 * @author Marco Traversari
 * @version $Revision: 1.2 $ $Date: 2011-10-20 16:18:52 $
 */
public class HTMLLayout extends Layout {

	private DateUtil dateUtil = null;

	protected final int BUF_SIZE = 256;

    protected final int MAX_CAPACITY = 1024;

    private static String TRACE_PREFIX = "<br>&nbsp;&nbsp;&nbsp;&nbsp;";

    // output buffer appended to when format() is invoked
    private StringBuffer sbuf = new StringBuffer(BUF_SIZE);

    // Print no location info by default
    boolean locationInfo = false;

    private String title = "Log4J Log Messages";

    /**
     * The <b>LocationInfo</b> option takes a boolean value. By default, it is
     * set to false which means there will be no location information output by
     * this layout. If the the option is set to true, then the file name and
     * line number of the statement at the origin of the log statement will be
     * output.
     *
     * <p>
     * If you are embedding this layout within an then make sure to set the
     * <b>LocationInfo</b> option of that appender as well.
     */
    public void setLocationInfo(boolean flag) {
        locationInfo = flag;
    }

    /**
     * Returns the current value of the <b>LocationInfo</b> option.
     */
    public boolean getLocationInfo() {
        return locationInfo;
    }

    /**
     * The <b>Title</b> option takes a String value. This option sets the
     * document title of the generated HTML document.
     *
     * <p>
     * Defaults to 'Log4J Log Messages'.
     */
    public void setTitle(String title) {
        this.title = title;
    }

    /**
     * Returns the current value of the <b>Title</b> option.
     */
    public String getTitle() {
        return title;
    }

    /**
     * Returns the content type output by this layout, i.e "text/html".
     */
    public String getContentType() {
        return "text/html";
    }

    /**
     * No options to activate.
     */
    public void activateOptions() {
    }

    /**
     * format
     * @param event
     * @return string
     */
    public String format(LoggingEvent event) {
    	initTimer();
        if (sbuf.capacity() > MAX_CAPACITY) {
            sbuf = new StringBuffer(BUF_SIZE);
        } else {
            sbuf.setLength(0);
        }
        sbuf.append("<tr class=\"lfs\">");
        sbuf.append("<td class=\"td7\" nowrap=\"nowrap\">");
        sbuf.append(dateUtil.getString(new Date(event.timeStamp)));
        sbuf.append("</td>");
        sbuf.append("<td class=\"td2\">");
        if (event.getNDC() != null) {
            sbuf.append(Transform.escapeTags(event.getNDC()));
        }
        sbuf.append("</td>");
        sbuf.append("<td class=\"td2\">");
        sbuf.append(event.getLevel());
        sbuf.append("</span>");
        sbuf.append("</td>");
        String loggerName = event.getLoggerName();
        String shortLoggerName = loggerName.substring(loggerName.lastIndexOf(".") + 1);
        sbuf.append("<td class=\"td7\">");
        sbuf.append("<span title=\"").append(loggerName).append("\">");
        sbuf.append(shortLoggerName);
        sbuf.append("</span>");
        sbuf.append("</td>");
        sbuf.append("<td class=\"rgs\">");
        sbuf.append(formatMessage(event));
        sbuf.append("</td>");
        sbuf.append("</tr>").append(LINE_SEP);
        String[] s = event.getThrowableStrRep();
        if (s != null) {
            sbuf.append("<tr><td class=\"err\" colspan=\"6\">");
            appendThrowableAsHTML(s, sbuf);
            sbuf.append("</td></tr>").append(LINE_SEP);
        }

        return sbuf.toString();
    }

    void appendThrowableAsHTML(String[] s, StringBuffer sbuf) {
        if (s != null) {
            int len = s.length;
            if (len == 0)
                return;
            sbuf.append(Transform.escapeTags(s[0]));
            sbuf.append(LINE_SEP);
            for (int i = 1; i < len; i++) {
                sbuf.append(TRACE_PREFIX);
                sbuf.append(Transform.escapeTags(s[i]));
                sbuf.append(LINE_SEP);
            }
        }
    }

    /**
     * Returns appropriate HTML headers.
     * @return headers
     * @see org.apache.log4j.Layout#getHeader()
     */
    public String getHeader() {
        StringBuffer sbuf = new StringBuffer();
        sbuf.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">").append(LINE_SEP);
        sbuf.append("<html>").append(LINE_SEP);
        sbuf.append("<head>").append(LINE_SEP);
        sbuf.append("<title>").append(title).append("</title>").append(LINE_SEP);
        sbuf.append("<meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\"/>").append(LINE_SEP);
        sbuf.append("<style type=\"text/css\">").append(LINE_SEP);
        sbuf.append("<!--").append(LINE_SEP);
        sbuf.append("body {font-family: verdana, arial;}").append(LINE_SEP);
        sbuf.append("table {width: 100%; border-spacing: 1px;}").append(LINE_SEP);
        //sbuf.append("table td {padding: 0.5px}").append(LINE_SEP);
        sbuf.append("table th {background: #2759AF; font-size: 11pt; color: #FFFFFF; text-align: left;}").append(LINE_SEP);
        sbuf.append(".td7 {width: 7%}").append(LINE_SEP);
        sbuf.append(".td2 {width: 2%}").append(LINE_SEP);
        sbuf.append(".lfs { font-size: 8pt; background-color: #F0F0F0;}").append(LINE_SEP);
        sbuf.append(".rgs {font-size: 10pt; background-color: #FFFFFF;}").append(LINE_SEP);
        sbuf.append(".dbg {font-size: 10pt; color: #EF871D;}").append(LINE_SEP);
        sbuf.append(".dbgb {font-size: 10pt; color: #D2A41C;}").append(LINE_SEP);
        sbuf.append(".inf {font-size: 10pt; color: #1B3678;}").append(LINE_SEP);
        sbuf.append(".infb { font-size: 10pt; color: #418848;}").append(LINE_SEP);
        sbuf.append(".err { font-size: 10pt; color: #FF0000;}").append(LINE_SEP);
        sbuf.append("-->").append(LINE_SEP);
        sbuf.append("</style>").append(LINE_SEP);
        sbuf.append("</head>").append(LINE_SEP);
        sbuf.append("<body>").append(LINE_SEP);
        sbuf.append("<table>").append(LINE_SEP);
        sbuf.append("<tr>");
        sbuf.append("<th>Time</th>");
        sbuf.append("<th>IP</th>");
        sbuf.append("<th>Level</th>");
        sbuf.append("<th>Class</th>");
        sbuf.append("<th>Message</th>");
        sbuf.append("</tr>");
        return sbuf.toString();
    }

    /**
     * Returns the appropriate HTML footers.
     */
    public String getFooter() {
        StringBuffer sbuf = new StringBuffer();
        sbuf.append("</table>").append(LINE_SEP);
        sbuf.append("</body></html>");
        return sbuf.toString();
    }

    /**
     * The HTML layout handles the throwable contained in logging events. Hence,
     * this method return <code>false</code>.
     */
    public boolean ignoresThrowable() {
        return false;
    }

    /**
     * formatMessage
     * @param event
     * @return
     */
    private String formatMessage(LoggingEvent event) {
    	String message = event.getMessage().toString();
    	Level level = event.getLevel();
    	if (level == Level.DEBUG) {
    		message = "<span class=\"dbg\">" + message + "</span><br/>";

    	} else if (level == Level.INFO) {
    		message = "<span class=\"inf\">" + message + "</span><br/>";
    	}
    	return message;
    }

    /**
     * initTimer
     */
    private void initTimer() {
    	if (dateUtil == null) {
    		dateUtil = new DateUtil("yy-MM-dd HH:mm:ss");
    	}
    }
}
